package com.bright.ghj.common.handler;

import com.bright.ghj.common.pojo.bo.RestResult;
import com.bright.ghj.common.util.CollectionUtil;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.Set;

/**
 * @Author txf
 * @Author Tz
 * @Date 2022/6/20 9:43
 * @Description 全局异常处理程序
 */
//@ControllerAdvice
public class GlobalExceptionHandler {

    @ResponseBody
    @ExceptionHandler(value = Throwable.class)
    public RestResult errorHandler(Exception e) {
        e.printStackTrace();
        // GBK中文乱码 转换成UTF8
//        String message;
//        try {
//            message = new String(e.getMessage().getBytes("GBK"), StandardCharsets.UTF_8);
//        } catch (UnsupportedEncodingException ex) {
//            throw new RuntimeException(ex);
//        }
        String message = e.getMessage();
        return RestResult.fail(message);
    }

    /**
     * 普通参数(非 java bean)校验出错时抛出
     * <p>
     * 使用 Validated 注解生效 {@link org.springframework.validation.annotation.Validated}
     * <p>
     * 结合使用 {@link javax.validation.constraints.NotNull}, {@link javax.validation.constraints.Min}等
     *
     * @param constraintViolationException 普通参数校验失败的异常
     * @return                             校验失败的信息
     */
    @ResponseBody
    @ExceptionHandler(value = ConstraintViolationException.class)
    public RestResult constraintViolationHandler(ConstraintViolationException constraintViolationException) {
        Set<ConstraintViolation<?>> violations = constraintViolationException.getConstraintViolations();

        if (CollectionUtil.isEmpty(violations)) {
            return RestResult.fail("参数校验异常");
        }

        StringBuilder message = new StringBuilder();
        // 将验证失败的信息转换为自定义的错误信息
        for (ConstraintViolation<?> item : violations) {
            String propertyPath = item.getPropertyPath().toString();
            message.append(", ")
                    .append(propertyPath.split("\\.")[1]).append(": ")
                    .append(item.getMessage())
                    .append(" (实际值: ")
                    .append(Objects.isNull(item.getExecutableParameters()[0]) ? "" : item.getExecutableParameters()[0].toString())
                    .append(")");
        }
        return RestResult.fail(message.substring(2));
    }

    /**
     * 请求参数绑定到java bean上，参数校验异常全局处理
     * <p>
     * 使用 Valid 注解生效 {@link javax.validation.Valid}
     *
     * @param bindException java bean参数校验失败的异常
     * @return                                校验失败的信息
     */
    @ResponseBody
    @ExceptionHandler(value = BindException.class)
    public RestResult bindException(BindException bindException) {
        BindingResult bindingResult = bindException.getBindingResult();
        StringBuilder message = new StringBuilder();
        if (bindingResult.hasErrors()) {
            for (ObjectError error : bindingResult.getAllErrors()) {
                message.append(", ");
                if (error instanceof FieldError) {
                    message.append(((FieldError) error).getField()).append(": ");
                }
                message.append(error.getDefaultMessage() == null ? "" : error.getDefaultMessage());
            }
            return RestResult.fail(message.substring(2));
        } else {
            return RestResult.fail("参数校验异常");
        }

    }
}
